package cn.thornbird.orgsync.service.impl;

import cn.thornbird.orgsync.entity.Certificate;
import cn.thornbird.orgsync.entity.CertificateDetail;
import cn.thornbird.orgsync.entity.Company;
import cn.thornbird.orgsync.entity.status.AppType;
import cn.thornbird.orgsync.exception.BadRequestException;
import cn.thornbird.orgsync.exception.ForbiddenException;
import cn.thornbird.orgsync.exception.NotFoundException;
import cn.thornbird.orgsync.model.UserData;
import cn.thornbird.orgsync.model.combined.CertificateObject;
import cn.thornbird.orgsync.repository.CertificateDetailRepository;
import cn.thornbird.orgsync.repository.CertificateRepository;
import cn.thornbird.orgsync.repository.CompanyRepository;
import cn.thornbird.orgsync.service.CertificateService;
import cn.thornbird.orgsync.vo.record.CertificateDetailRecord;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;

@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class CertificateServiceImpl extends BaseService<CertificateRepository, Certificate>
        implements CertificateService {

    private final CertificateRepository certificateRepository;

    private final CertificateDetailRepository certificateDetailRepository;

    private final CompanyRepository companyRepository;

    @Override
    public CertificateObject find(UserData userData, String id) throws ForbiddenException, NotFoundException {
        CertificateObject certificateObject = findCertificateObject(id);
        checkAuthority(userData, certificateObject.getCertificate());
        return certificateObject;
    }

    @Override
    public CertificateDetail findDetail(UserData userData, String companyId, AppType appType)
            throws ForbiddenException, NotFoundException {
        Assert.notNull(companyId, "公司ID不能为空");
        Certificate certificate = certificateRepository.findFirstByUserIdAndCompanyId(userData.getId(), companyId);
        if (certificate == null) {
            throw new NotFoundException("相关公司的同步凭证不存在");
        }

        CertificateDetail certificateDetail = null;
        checkAuthority(userData, certificate);
        List<CertificateDetail> certificateDetails = certificateDetailRepository.findAllByCertificateIdOrderByAppType(
                certificate.getId());
        for (CertificateDetail detail : certificateDetails) {
            if (detail.getAppType() == appType) {
                certificateDetail = detail;
                break;
            }
        }
        if (certificateDetail == null) {
            throw new NotFoundException("指定应用类型的同步凭证明细不存在");
        }

        return certificateDetail;
    }

    @Override
    public List<CertificateObject> query(UserData userData) {
        List<CertificateObject> list = new ArrayList<>();
        if (!userData.hasAuthority(UserData.ADMIN) && !userData.hasAuthority(UserData.AUTHORIZED)) {
            return list;
        }

        List<Certificate> certificates = certificateRepository.findAllByUserIdOrderByCreatedAt(userData.getId());
        List<CertificateDetail> details = certificateDetailRepository.findAllByUserId(userData.getId());
        Map<String, List<CertificateDetail>> detailMap = new HashMap<>();
        Set<String> companyIds = new HashSet<>();
        List<Company> companies;
        Map<String, Company> companyMap = new HashMap<>();
        for (CertificateDetail detail : details) {
            List<CertificateDetail> records;
            if (detailMap.containsKey(detail.getCertificateId())) {
                records = detailMap.get(detail.getCertificateId());
            } else {
                records = new ArrayList<>();
                detailMap.put(detail.getCertificateId(), records);
            }
            records.add(detail);
        }
        for (Certificate certificate : certificates) {
            companyIds.add(certificate.getCompanyId());
        }
        companies = companyRepository.findAllByIdIn(Arrays.asList(companyIds.toArray(new String[0])));
        for (Company company : companies) {
            companyMap.put(company.getId(), company);
        }
        for (Certificate certificate : certificates) {
            CertificateObject object = new CertificateObject();
            List<CertificateDetail> records;
            if (detailMap.containsKey(certificate.getId())) {
                records = detailMap.get(certificate.getId());
            } else {
                records = new ArrayList<>();
            }
            object.setCertificate(certificate);
            object.setDetails(records);
            object.setCompany(companyMap.get(certificate.getCompanyId()));
            list.add(object);
        }
        return list;
    }

    @Override
    public CertificateObject add(UserData userData, String companyId)
            throws BadRequestException, ForbiddenException, NotFoundException {
        checkAuthority(userData, null);
        Assert.notNull(companyId, "公司ID不能为空");

        Company company = companyRepository.findFirstById(companyId);
        if (company == null) {
            throw new NotFoundException("公司不存在");
        }

        Certificate certificate = certificateRepository.findFirstByUserIdAndCompanyId(userData.getId(), companyId);
        if (certificate != null) {
            throw new BadRequestException("同步凭证已存在");
        }

        certificate = new Certificate();
        certificate.setCompanyId(companyId);
        certificate.setUserId(userData.getId());
        certificate.generateNewId();
        certificateRepository.save(certificate);
        return findCertificateObject(certificate.getId());
    }

    @Override
    public CertificateObject save(UserData userData, String id, List<CertificateDetailRecord> details)
            throws BadRequestException, ForbiddenException, NotFoundException {
        Assert.notNull(id, "ID不能为空");
        Certificate certificate = findFirstById(certificateRepository, id);
        checkAuthority(userData, certificate);

        List<CertificateDetail> list = certificateDetailRepository.findAllByCertificateIdOrderByAppType(id);
        Map<AppType, CertificateDetailRecord> map = new HashMap<>();
        String message = null;
        details = details == null ? new ArrayList<>() : details;
        for (CertificateDetailRecord record : details) {
            if (map.containsKey(record.getAppType())) {
                message = "同步凭证App类型重复: " + record.getAppType().name();
                break;
            }
            map.put(record.getAppType(), record);
        }
        if (message != null) {
            throw new BadRequestException(message);
        }

        for (CertificateDetail detail : list) {
            if (map.containsKey(detail.getAppType())) {
                CertificateDetailRecord record = map.get(detail.getAppType());
                detail.setData(record.getData());
                certificateDetailRepository.save(detail);
                map.remove(detail.getAppType());
            } else {
                certificateDetailRepository.logicDelete(detail.getId());
            }
        }
        for (CertificateDetailRecord record : map.values()) {
            CertificateDetail detail = new CertificateDetail();
            detail.setCertificateId(id);
            detail.setAppType(record.getAppType());
            detail.setData(record.getData());
            detail.generateNewId();
            certificateDetailRepository.save(detail);
        }
        return findCertificateObject(id);
    }

    @Override
    public CertificateObject delete(UserData userData, String id) throws ForbiddenException, NotFoundException {
        CertificateObject object = findCertificateObject(id);
        checkAuthority(userData, object.getCertificate());
        certificateRepository.logicDelete(id);
        certificateDetailRepository.logicDeleteRecords(id);
        return object;
    }

    private void checkAuthority(UserData userData, Certificate certificate) throws ForbiddenException {
        if (!userData.hasAuthority(UserData.ADMIN) && !userData.hasAuthority(UserData.AUTHORIZED)) {
            throw new ForbiddenException("禁止操作，没有权限");
        }

        if (certificate != null && !userData.getUsername().equals(certificate.getCreatedBy())) {
            throw new ForbiddenException("禁止操作，没有权限");
        }
    }

    private CertificateObject findCertificateObject(String id) throws NotFoundException {
        Assert.notNull(id, "ID不能为空");
        CertificateObject object = new CertificateObject();
        Certificate certificate = findFirstById(certificateRepository, id);
        List<CertificateDetail> details = certificateDetailRepository.findAllByCertificateIdOrderByAppType(id);
        object.setCertificate(certificate);
        object.setCompany(companyRepository.findFirstById(certificate.getCompanyId()));
        object.setDetails(details);
        return object;
    }

}
